Skip to content

OCR integration #13313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 59 commits into
base: main
Choose a base branch
from

Conversation

Kaan0029
Copy link
Contributor

@Kaan0029 Kaan0029 commented Jun 12, 2025

Closes #13267.

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • [.] Change in CHANGELOG.md described in a way that is understandable for the average user (if change is visible to the user)
  • [.] Tests created for changes (if applicable)
  • [.] Manually tested changed features in running JabRef (always required)
  • [.] Screenshots added in PR description (if change is visible to the user)
  • [.] Checked developer's documentation: Is the information available and up to date? If not, I outlined it in this pull request.
  • [.] Checked documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request to the documentation repository.

@calixtus calixtus changed the title Initial implementation using tess4j OCR integration Jun 12, 2025
@subhramit
Copy link
Member

Your pull request conflicts with the target branch.

Please merge upstream/main with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

Tip for future - always take a fresh pull from upstream/main before beginning to work on a branch (if there has been a decent time gap).

@koppor koppor added this to the 6.0 milestone Jul 4, 2025
@jabref-machine
Copy link
Collaborator

Your code currently does not meet JabRef's code guidelines. We use Checkstyle to identify issues. You can see which checks are failing by locating the box "Some checks were not successful" on the pull request page. To see the test output, locate "Tests / Checkstyle (pull_request)" and click on it.

In case of issues with the import order, double check that you activated Auto Import. You can trigger fixing imports by pressing Ctrl+Alt+O to trigger Optimize Imports.

Please carefully follow the setup guide for the codestyle. Afterwards, please run checkstyle locally and fix the issues, commit, and push.

@Kaan0029 Kaan0029 force-pushed the gsoc-ocr-tess4j-initial-implementation branch from 9f91505 to db1f577 Compare July 10, 2025 10:49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was maybe by mistake checked in. Follow the guide in the devdocs faq to undo this.

Comment on lines +26 to +29
if (StringUtil.isBlank(errorMessage)) {
errorMessage = "Unknown error occurred";
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am i missing something here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What did you mean, Carl?


this.ocrService = new OcrService(filePreferences);

// Log if OCR is not available but don't fail
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment simply restates what the code does in the next lines. It doesn't provide additional information about why this approach was chosen or any other valuable context.

}
return false; // nothing usable found
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching generic Exception is too broad and masks specific issues. Should catch specific exceptions like IOException or SecurityException for better error handling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, trag bot probably selected wrong lines, but overall he's right, the Exception is too generic

Copy link

trag-bot bot commented Jul 21, 2025

@trag-bot didn't find any issues in the code! ✅✨

Copy link

trag-bot bot commented Jul 21, 2025

@trag-bot didn't find any issues in the code! ✅✨

linkedFile.getFileType().equalsIgnoreCase("pdf") &&
linkedFile.findIn(databaseContext, filePreferences).isPresent()
);
this.ocrService = ocrService;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Field initialization is placed after the executable.set() call, which violates field initialization order best practices and could lead to potential null pointer issues.

this.filePreferences = filePreferences;
this.taskExecutor = taskExecutor;

// Only executable for existing PDF files
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment merely restates what the code does without providing additional insight or reasoning, violating the principle that comments should add new information.

Localization.lang("No text was found in the PDF.")
);
} else {
// Show preview
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trivial comment that doesn't add any new information beyond what's clearly visible in the code itself should be removed.

Copy link
Member

@InAnYan InAnYan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some refactoring comments

Localization.lang("Failed to initialize AI service. OCR functionality will be unavailable.") + "\n\n" +
Localization.lang("Error details: ") + e.getMessage());
// Set aiService to null - the application can continue without AI features
JabRefGUI.aiService = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it can't.

Trust me. It must be present and not null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is outdated, right?

dialogService,
taskExecutor);
Injector.setModelOrService(AiService.class, aiService);
} catch (OcrException e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the throw of exception and not use them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is outdated, right?

@@ -86,9 +97,46 @@ private ContextMenu createContextMenuForFile(LinkedFileViewModel linkedFile) {
factory.createMenuItem(StandardActions.DELETE_FILE, singleCommandFactory.build(StandardActions.DELETE_FILE, linkedFile))
);

// Add OCR menu item for PDF files
if (linkedFile.getFile().getFileType().equalsIgnoreCase("pdf")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to search a method in class FilesUtil (or FileUtil) like isPDF

@@ -121,7 +121,7 @@ private void applyDarkModeToWindow(Stage stage, boolean darkMode) {
return;
}

themeWindowManager.setDarkModeForWindowFrame(stage, darkMode);
// themeWindowManager.setDarkModeForWindowFrame(stage, darkMode);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this doesn't solve the original problem? Shouldn't you made a try/catch, so that other people who use JabRef could still use dark theme, if for some other machines it doesn't work


public AiService(AiPreferences aiPreferences,
FilePreferences filePreferences,
CitationKeyPatternPreferences citationKeyPatternPreferences,
NotificationService notificationService,
TaskExecutor taskExecutor
) {
) throws OcrException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the best idea

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is outdated, right?

/**
* Factory method for creating a success result.
*/
static OcrResult success(@NonNull String text) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove @NonNull and always assume that the input is not null

}
return false; // nothing usable found
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, trag bot probably selected wrong lines, but overall he's right, the Exception is too generic

getBoolean(OPEN_FILE_EXPLORER_IN_LAST_USED_DIRECTORY));
getBoolean(OPEN_FILE_EXPLORER_IN_LAST_USED_DIRECTORY),
// TODO: replace placeholder once real source tag / persistence is implemented
"");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are able to handle this. This is not hard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GSOC meta issue: OCR Integration in JabRef
7 participants